package com.oa.modules.approvalsec1.controller;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.HMac;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.gson.Gson;
import com.oa.common.utils.*;
import com.oa.modules.approvalsec1.entity.*;
import com.oa.modules.approvalsec1.service.*;
import com.oa.modules.approvalsec1.wx.ConfigUtil;
import com.oa.modules.approvalsec1.wx.HttpUtils;
import com.oa.modules.sys.controller.AbstractController;
import com.oa.modules.sys.entity.SysUserEntity;
import com.oa.modules.sys.entity.SysUserRoleEntity;
import com.oa.modules.sys.service.SysUserRoleService;
import com.oa.modules.sys.service.SysUserTokenService;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.cvm.v20170312.CvmClient;
import com.tencentcloudapi.cvm.v20170312.models.DescribeInstancesResponse;
import com.tencentcloudapi.tcr.v20190924.models.DescribeInstancesRequest;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.DatatypeConverter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.AlgorithmParameters;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.sql.Timestamp;
import java.util.*;


/**
 * 微信小程序
 *
 * @author jiangwei
 * @date 2021-03-16 09:47:45
 */
@RestController
@Api(tags = "小程序登录相关接口")
@RequestMapping("/wxLogin")
public class WxLoginController extends AbstractController {

    @Autowired
    private SysUserTokenService sysUserTokenService;

    @Autowired
    private SysUserRoleService sysUserRoleService;

    @Autowired
    private ExplorationCloudService explorationCloudService;

    @Autowired
    private RoomStoreService roomStoreService;

    @Autowired
    private CloudVideoService cloudVideoService;

    @Autowired
    private UserSocialService userSocialService;

    @Autowired
    private BiddProjectService biddProjectService;

    @Autowired
    private EnterpriseService enterpriseService;

    public static String callPush(String openid, String roomNum, String number) {
        //这里简单起见 我们每次都获取最新的token
        String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + getAccessToken();
        //拼接推送模板
        JSONObject xmlData = new JSONObject();
        xmlData.put("touser", openid);//用户的openid（要发送给那个用户，通常这里应该动态传进来的）
        xmlData.put("template_id", "Rf22caSDpqjKoNmirqcbPSBqV_zH96ReBxmKAODRZYU");//订阅消息模板id
        xmlData.put("miniprogramState", "developer");
        xmlData.put("page", "pages/videocall/videocall?thing3=" + roomNum);

        JSONObject data = new JSONObject();
        //办理事项
        JSONObject thing2 = new JSONObject();
        thing2.put("value", "齐河审批局邀请您进入视频会议");
        data.put("thing2", thing2);

        //您的号码
        JSONObject characterString1 = new JSONObject();
        characterString1.put("value", number);
        data.put("character_string1", characterString1);

        //办理窗口
        JSONObject thing3 = new JSONObject();
        thing3.put("value", roomNum);
        data.put("thing3", thing3);
        xmlData.put("data", data);
        String result = HttpUtils.post(url, xmlData.toString());
//        ResponseEntity<String> responseEntity =
//                restTemplate.postForEntity(url, xmlData.toString(), String.class);
        System.err.println(xmlData.toString());
        System.err.println(result);
        return result;
    }

    public static String noticePush(String openid, String matterType, String noticeContext, Date updateDate, Date saveDate) {
        //这里简单起见 我们每次都获取最新的token
        String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + getAccessToken();
        //拼接推送模板
        JSONObject xmlData = new JSONObject();
        xmlData.put("touser", openid);//用户的openid（要发送给那个用户，通常这里应该动态传进来的）
        xmlData.put("template_id", "CSRD8wHwXYu36kOCDZy9EXWs18m11U7HT1dVOxHKRhg");//订阅消息模板id
        xmlData.put("miniprogramState", "developer");
        xmlData.put("page", "");

        JSONObject data = new JSONObject();
        //业务类型
        JSONObject thing1 = new JSONObject();
        thing1.put("value", matterType);
        data.put("thing1", thing1);

        //当前进度
        JSONObject thing2 = new JSONObject();
        thing2.put("value", noticeContext);
        data.put("thing2", thing2);

        //更新时间
        JSONObject date3 = new JSONObject();
        date3.put("value", DateUtils.format(updateDate, "yyyy-MM-dd HH:mm"));
        data.put("date3", date3);

        //申请时间
        JSONObject date4 = new JSONObject();
        date4.put("value", DateUtils.format(saveDate, "yyyy-MM-dd HH:mm"));
        data.put("date4", date4);


        xmlData.put("data", data);
        String result = HttpUtils.post(url, xmlData.toString());
//        ResponseEntity<String> responseEntity =
//                restTemplate.postForEntity(url, xmlData.toString(), String.class);
        System.err.println(xmlData.toString());
        System.err.println(result);
        return result;
    }

    public static String getAccessToken() {
        RestTemplate restTemplate = new RestTemplate();
        Map<String, String> params = new HashMap<>();
        params.put("APPID", ConfigUtil.APPID);
        params.put("APPSECRET", ConfigUtil.App_Secret);
        ResponseEntity<String> responseEntity = restTemplate.getForEntity("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={APPID}&secret={APPSECRET}", String.class, params);
        String body = responseEntity.getBody();
        com.alibaba.fastjson.JSONObject object = JSON.parseObject(body);
        String Access_Token = object.getString("access_token");
        String expires_in = object.getString("expires_in");
        System.err.println("小程序token的有效时长为：" + expires_in);
        return Access_Token;
    }

    public static String BankAccountPush(String openid, String companyName, String socialCreditCode, String address, String callName, String transactor) {
        //这里简单起见 我们每次都获取最新的token
        String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + getAccessToken();
        //拼接推送模板
        JSONObject xmlData = new JSONObject();
        xmlData.put("touser", openid);//用户的openid（要发送给那个用户，通常这里应该动态传进来的）
        xmlData.put("template_id", "XwyBb_nSOP9wANJj9MESNadLoS1ILUUsZXJiY_2MoYM");//订阅消息模板id
        xmlData.put("miniprogramState", "developer");
        xmlData.put("page", "pages/accountmake/accountmake");

        JSONObject data = new JSONObject();

        //公司名称
        JSONObject thing1 = new JSONObject();
        thing1.put("value", companyName);
        data.put("thing1", thing1);

        //信用代码
        JSONObject thing2 = new JSONObject();
        thing2.put("value", socialCreditCode);
        data.put("character_string2", thing2);

        //地址
        JSONObject thing3 = new JSONObject();
        thing3.put("value", address);
        data.put("thing3", thing3);

        //法人
        JSONObject thing4 = new JSONObject();
        thing4.put("value", callName);
        data.put("thing4", thing4);

        //经办人
        JSONObject thing5 = new JSONObject();
        thing5.put("value", transactor);
        data.put("thing5", thing5);
        xmlData.put("data", data);
        String result = HttpUtils.post(url, xmlData.toString());
        return result;

    }

    public static String sign(String s, String key, String method) throws Exception {
        Mac mac = Mac.getInstance(method);
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes("UTF-8"), mac.getAlgorithm());
        mac.init(secretKeySpec);
        byte[] hash = mac.doFinal(s.getBytes("UTF-8"));
        return DatatypeConverter.printBase64Binary(hash);
    }

    public static String getStringToSign(TreeMap<String, Object> params) {
        StringBuilder s2s = new StringBuilder("GETtrtc.tencentcloudapi.com/?");
        // 签名时要求对参数进行字典排序，此处用TreeMap保证顺序
        for (String k : params.keySet()) {
            s2s.append(k).append("=").append(params.get(k).toString()).append("&");
        }
        return s2s.toString().substring(0, s2s.length() - 1);
    }

    public static String getUrl(TreeMap<String, Object> params) throws UnsupportedEncodingException {
        StringBuilder url = new StringBuilder("https://cvm.tencentcloudapi.com/?");
        // 实际请求的url中对参数顺序没有要求
        for (String k : params.keySet()) {
            // 需要对请求串进行urlencode，由于key都是英文字母，故此处仅对其value进行urlencode
            url.append(k).append("=").append(URLEncoder.encode(params.get(k).toString(), "UTF-8")).append("&");
        }
        return url.toString().substring(0, url.length() - 1);
    }


    public static String OpenAccountPush(String openid, String companyName, String userName, String phone, String companyCode, String address) {
        //这里简单起见 我们每次都获取最新的token
        String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + getAccessToken();
        //拼接推送模板
        JSONObject xmlData = new JSONObject();
        xmlData.put("touser", openid);//用户的openid（要发送给那个用户，通常这里应该动态传进来的）
        xmlData.put("template_id", "g8Q7izzGZzlh7A60R15QRUWrgscRIgOFNoZC9tzLRf0");//订阅消息模板id
        xmlData.put("miniprogramState", "developer");
        xmlData.put("page", "pages/accountmake/accountmake");

        JSONObject data = new JSONObject();

        //公司名称
        JSONObject thing3 = new JSONObject();
        thing3.put("value", companyName);
        data.put("thing3", thing3);

        //申请人
        JSONObject thing1 = new JSONObject();
        thing1.put("value", userName);
        data.put("thing1", thing1);

        //手机号
        JSONObject number2 = new JSONObject();
        number2.put("value", phone);
        data.put("phone_number2", number2);

        //信用代码
        JSONObject string4 = new JSONObject();
        string4.put("value", companyCode);
        data.put("character_string4", string4);

        //办理地址
        JSONObject thing5 = new JSONObject();
        thing5.put("value", address);
        data.put("thing5", thing5);


        xmlData.put("data", data);
        String result = HttpUtils.post(url, xmlData.toString());
//        ResponseEntity<String> responseEntity =
//                restTemplate.postForEntity(url, xmlData.toString(), String.class);
        System.err.println(xmlData.toString());
        System.err.println(result);
        return result;
    }

    @ResponseBody
    @ApiOperation(value = "获取录制的本会议的录制视频")
    @PostMapping(value = "/api/wx/getLuzhiUrl")
    public void getLuzhiUrl(@RequestBody HashMap<String, String> map) {
        //消息类型，当 event_type 为100时，表示该回调消息为录制文件生成的消息。
        String eventType = map.get("event_type");
        System.out.println("eventType:" + eventType);
        //即直播 CDN 的 streamId，您可以在进房时通过设置 TRTCParams 中的 streamId 字段指定（推荐），也可以在调用 TRTCCloud 的 startPublishing 接口时通过参数 streamId 来指定。
        String streamId = map.get("stream_id");
        System.out.println("streamId:" + streamId);
        //用户名的 Base64 编码。
        String userId = map.get("stream_param.userid");
        System.out.println("userId:" + userId);
        //自定义字段，您可以通过设置 TRTCParams 中的 userDefineRecordId 字段指定
        String userdefnerecordId = map.get(" stream_param.userdefinerecordid");
        System.out.println("userdefnerecordId:" + userdefnerecordId);
        //录制文件的观看地址，可以用于 点播回放。
        String videoUrl = map.get("video_url");
        System.out.println("videoUrl:" + videoUrl);

        String[] streamIds = streamId.split("_");
        //先查room表获取云踏勘id
        RoomStoreEntity room = roomStoreService.getOne(new QueryWrapper<RoomStoreEntity>().eq("room_num", streamIds[1]));
        if (room != null) {
            if (room.getResultUrl() != null && !"".equals(room.getResultUrl())) {
                room.setResultUrl(room.getResultUrl() + "," + videoUrl);
            } else {
                room.setResultUrl(videoUrl);
            }
            roomStoreService.updateById(room);
            CloudVideoEntity cloudVideoEntity = new CloudVideoEntity();
            cloudVideoEntity.setId(AppUtils.getUUID());
            cloudVideoEntity.setCloudId(room.getExplorationCloudId());
            cloudVideoEntity.setNumTimes(room.getNumTimes());
            cloudVideoEntity.setRoomNum(streamIds[1]);
            cloudVideoEntity.setResultUrl(videoUrl);
            cloudVideoEntity.setCreateDate(new Date());
            cloudVideoEntity.setCreateOper("1");
            cloudVideoService.save(cloudVideoEntity);
        }
    }

    @ResponseBody
    @ApiOperation(value = "获取用户手机号")
    @PostMapping(value = "/api/wx/getPhoneNumber")
    public Object getPhoneNumber(@RequestBody Map<String, Object> map) {
        String userId = map.get("userId").toString();
        String encryptedData = map.get("encryptedData").toString();
        String session_key = map.get("session_key").toString();
        String iv = map.get("iv").toString();
        // 被加密的数据
        byte[] dataByte = Base64.decode(encryptedData);
        // 加密秘钥
        byte[] keyByte = Base64.decode(session_key);
        // 偏移量
        byte[] ivByte = Base64.decode(iv);
        try {
            //如果密钥不足16位，那么就补足.  这个if 中的内容很重要
            int base = 16;
            if (keyByte.length % base != 0) {
                int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);
                byte[] temp = new byte[groups * base];
                Arrays.fill(temp, (byte) 0);
                System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
                keyByte = temp;
            }
            // 初始化
            Security.addProvider(new BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
            AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
            parameters.init(new IvParameterSpec(ivByte));
            cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化
            byte[] resultByte = cipher.doFinal(dataByte);
            if (null != resultByte && resultByte.length > 0) {
                String result = new String(resultByte, "UTF-8");
                System.out.println("================" + result);
                com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(result);
                String phone = jsonObject.get("phoneNumber").toString();
                SysUserEntity user = sysUserService.getById(userId);
                if (user != null) {
                    user.setMobile(phone);
                    sysUserService.updateById(user);
                    return R.ok();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.error();
    }

    @ResponseBody
    @ApiOperation(value = "授权获取用户唯一标识")
    @RequestMapping(value = "/api/wx/getOpenId", method = {RequestMethod.POST, RequestMethod.GET})
    //小程序端的自动登录接口Login接口
    public R getOpenId(HttpServletRequest request, HttpServletResponse response,
                       @RequestBody(required = false) HashMap<String, String> codeMap) {
        String params = "appid=" + ConfigUtil.APPID + "&secret=" + ConfigUtil.App_Secret + "&js_code=" + codeMap.get("code") + "&grant_type=authorization_code";
        String result = HttpUtil.sendGet("https://api.weixin.qq.com/sns/jscode2session", params);
        if (result.indexOf("errcode") >= 0) {
            return R.error(result);
        } else {
            JSONObject jsonObject = new JSONObject(result);
            String openid = jsonObject.get("openid").toString();
            String session_key = jsonObject.get("session_key").toString();
            Map<String, Object> map = new HashMap<String, Object>();
            Map<String, Object> data = new HashMap<String, Object>();
            //通过查询openid去获取用户id
            map.put("openId", openid);
            map.put("session_key", session_key);
            List<SysUserEntity> userList = sysUserService.qryByOpenId(openid);
            if (userList != null && userList.size() > 0) {
                SysUserEntity userEntity = userList.get(0);
                //根据用户id获取用户企业名称
                EnterpriseEntity enterprise = enterpriseService.getOne(new QueryWrapper<EnterpriseEntity>().eq("user_id", userEntity.getUserId()));
                UserSocialEntity socialEntity = userSocialService.getOne(new QueryWrapper<UserSocialEntity>().eq("USER_TEL", userEntity.getMobile()));
                if (socialEntity != null) {
                    userEntity.setSocialType(socialEntity.getSocialType());
                }
                List<Long> roleIds = sysUserRoleService.queryRoleIdList(userList.get(0).getUserId());
                userEntity.setRoleIdList(roleIds);
                if (roleIds == null || roleIds.size() < 0) {
                    map.put("msg", "该用户未拥有角色");
                } else if (roleIds!=null&&roleIds.size()>0&&roleIds.get(0) == 6) {
                    userEntity.setCompany(enterprise.getEnterpriseName());
                } else {
                    userEntity.setCompany(null);
                }
                int isPushProject = biddProjectService.count(new QueryWrapper<BiddProjectEntity>().eq("create_order", userEntity.getUserId().toString()));
                if (isPushProject != 0) userEntity.setIsPushProject(true);
                map.put("user", userEntity);
            }
            data.put("data", map);
            return R.ok(data);
        }
    }

    @ResponseBody
    @ApiOperation(value = "微信用户信息保存")
    @PostMapping(value = "/api/wx/saveUserInfo")
    public R saveUserInfo(@RequestBody HashMap<String, String> map) {
        JSONObject jsonObject = new JSONObject(map.get("userInfo"));
        System.out.println(jsonObject);
        long id = System.currentTimeMillis();

        //通过查询openid去获取用户id
        List<SysUserEntity> userList = sysUserService.qryByOpenId(jsonObject.get("openid").toString());
        if (userList.size() == 0) {
            SysUserEntity user = new SysUserEntity();
            user.setWxOpenId(jsonObject.get("openid").toString());
            user.setUserId(id);
            user.setCreateTime(new Date());
            user.setStatus(0);
            user.setNickName(jsonObject.get("nickName").toString());
            user.setImage(jsonObject.get("avatarUrl").toString());
            user.setImageHtmlUrl(jsonObject.get("avatarUrl").toString());
            user.setWxImageUrl(jsonObject.get("avatarUrl").toString());
            user.setUsername(jsonObject.get("nickName").toString());
            user.setName(jsonObject.get("nickName").toString());
            user.setCreateUserId(1l);
            sysUserService.save(user);
            //生成token，并保存到数据库
            R r = sysUserTokenService.createToken(id);
            SysUserRoleEntity userRole = new SysUserRoleEntity();
            userRole.setUserId(user.getUserId());
            userRole.setRoleId(Convert.toLong(jsonObject.get("roleId")));
            sysUserRoleService.save(userRole);
            LambdaQueryWrapper<SysUserRoleEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(SysUserRoleEntity::getUserId, id);
            SysUserRoleEntity sysUserRoleEntity = sysUserRoleService.getOne(lambdaQueryWrapper);
            List<Long> list = new ArrayList<>();
            list.add(sysUserRoleEntity.getRoleId());
            user.setRoleIdList(list);
            r.put("user", user);
            Map<String, Object> data = new HashMap<String, Object>();
            data.put("data", r);
            System.out.println(data.toString());
            return R.ok(data);
        } else if (userList.size() == 1) {
            Map<String, Object> data = new HashMap<String, Object>();
            //通过查询openid去获取用户id
            data.put("openId", jsonObject.get("openid").toString());
            userList.get(0).setNickName(jsonObject.get("nickName").toString());
            userList.get(0).setImage(jsonObject.get("avatarUrl").toString());
            userList.get(0).setImageHtmlUrl(jsonObject.get("avatarUrl").toString());
            userList.get(0).setWxImageUrl(jsonObject.get("avatarUrl").toString());
            userList.get(0).setUsername(jsonObject.get("nickName").toString());
            sysUserService.update(userList.get(0));
            R r = sysUserTokenService.createToken(Long.valueOf(userList.get(0).getUserId()));
            List<Long> roleIds = sysUserRoleService.queryRoleIdList(userList.get(0).getUserId());
            userList.get(0).setRoleIdList(roleIds);
            r.put("user", userList.get(0));
            data.put("data", r);
            System.out.println(data.toString());
            return R.ok(data);
        }
        return R.error("数据库中有多条该用户数据！");
    }

    @ResponseBody
    @ApiOperation(value = "解散房间")
    @PostMapping(value = "/api/wx/dismiss")
    public R dismiss(@RequestBody HashMap<String, String> params) throws Exception {
        Gson gson = new Gson();
        TreeMap<String, Object> map = new TreeMap<>();
        map.put("Action", "DismissRoom");
        map.put("Version", "2019-07-22");
        map.put("Region", "ap-beijing");
        map.put("SdkAppId", "1400492536");
        map.put("RoomId", params.get("roomId"));
        map.put("Timestamp", System.currentTimeMillis() / 1000);
        map.put("Nonce", new Random().nextInt(java.lang.Integer.MAX_VALUE));
        map.put("SecretId", "AKID5ukOluq88tUpvlAsDI8iBUgfOFrEl8h9");
        map.put("Signature", sign(getStringToSign(map), "MRebKmhkgNr54YmjXpqZnSs1tVsxoYoo", "HmacSHA1"));
        String body = HttpRequest.get("https://trtc.tencentcloudapi.com/")
                .form(new HashMap<>(map))
                .execute().body();
        System.out.println(body);
        return R.ok().put("result", body);
    }

}
